package com.alks.function.service.impl.stockdept.pcfactorystockquery;

import com.alibaba.excel.util.StringUtils;
import com.alks.common.aop.AutoPageAop;
import com.alks.common.data.dto.SysUserTokenDTO;
import com.alks.common.data.thread.UserIdThread;
import com.alks.common.utils.beanutils.ArrayUtils;
import com.alks.common.utils.beanutils.BeanUtil;
import com.alks.entity.data.entity.HgMtlRelation;
import com.alks.entity.data.entity.PcDrawReplace2;
import com.alks.entity.data.entity.PcMtlAcc;
import com.alks.entity.data.entity.PcMtlCheck;
import com.alks.entity.data.response.ResponseInfo;
import com.alks.entity.exception.ServiceErrorException;
import com.alks.function.data.dto.stockdept.pcfactorystockwork.InStkDtlDto;
import com.alks.function.data.dto.stockdept.pcfactorystockwork.MtlSubDto;
import com.alks.function.data.dto.stockdept.pcfactorystockwork.SubMtlDto;
import com.alks.function.data.request.stockdept.pcfactorystockwork.*;
import com.alks.function.data.vo.controller.stockdept.HgMtlRelationVo;
import com.alks.function.mapper.stockdept.pcfactorystockquery.SD_SQ_PcDrawReplace2Mapper;
import com.alks.function.mapper.stockdept.pcfactorystockquery.SD_SQ_PcMtlAccMapper;
import com.alks.function.mapper.stockdept.pcfactorystockquery.SD_SQ_PcMtlCheckMapper;
import com.alks.function.service.stockdept.pcfactorystockquery.IHgMtlService;
import com.alks.function.service.stockdept.pcfactorystockquery.IPcMtlUDService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import jodd.util.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

import static com.alks.entity.data.enums.ResultCodeEnum.*;

@Slf4j
@Service
@RequiredArgsConstructor
public class PcMtlUDServiceImpl extends ServiceImpl<SD_SQ_PcMtlCheckMapper, PcMtlCheck> implements IPcMtlUDService {
    private final SD_SQ_PcMtlCheckMapper checkMapper;
    private final SD_SQ_PcDrawReplace2Mapper replace2Mapper;
    private final SD_SQ_PcMtlAccMapper accMapper;
    private final IHgMtlService hgMtlService;

    @AutoPageAop
    @Override
    public ResponseInfo inStockDetailQuery(IStockDtlRequest request) {
        /*输入检测*/
        if (request.getRecDateStart() != null && request.getRecDateEnd() != null && request.getRecDateStart().isAfter(request.getRecDateEnd())) {
            return ResponseInfo.error("起始时间晚于结束时间", TIME_IS_ERROR.getCode());
        }
        String companyId = UserIdThread.get().getCompanyId();
        /*获取数据*/
        List<PcMtlCheck> checks = lambdaQuery()
                .select(PcMtlCheck::getSlipType, PcMtlCheck::getRecNo, PcMtlCheck::getRecDate, PcMtlCheck::getSendDate, PcMtlCheck::getSendNo,
                        PcMtlCheck::getPurNo, PcMtlCheck::getVendorName, PcMtlCheck::getPurLot, PcMtlCheck::getMtlColor, PcMtlCheck::getMtlName,
                        PcMtlCheck::getMtlSpec, PcMtlCheck::getMtlUnit, PcMtlCheck::getKgQty, PcMtlCheck::getSendQty, PcMtlCheck::getSysUser, PcMtlCheck::getCfmFlag,
                        PcMtlCheck::getMtlNo, PcMtlCheck::getCompanyId,PcMtlCheck::getReqNo,PcMtlCheck::getPrimaryId,PcMtlCheck::getAcceptQty)
                .eq(PcMtlCheck::getCompanyId, companyId)
                .eq(PcMtlCheck::getRecFlag, "Y")
                .like(!request.getRecNo().isEmpty(), PcMtlCheck::getRecNo, request.getRecNo())
                .like(!request.getPurLot().isEmpty(), PcMtlCheck::getPurLot, request.getPurLot())
                .like(!request.getMtlName().isEmpty(), PcMtlCheck::getMtlName, request.getMtlName())
                .le(request.getRecDateStart() != null, PcMtlCheck::getRecDate, request.getRecDateStart())
                .ge(request.getRecDateEnd() != null, PcMtlCheck::getRecDate, request.getRecDateEnd())
                .orderByDesc(PcMtlCheck::getRecNo).list();
        Page<PcMtlCheck> page = (Page<PcMtlCheck>) checks;
        List<PcMtlCheck> list = lambdaQuery().select(PcMtlCheck::getSendQty)
                .eq(PcMtlCheck::getCompanyId, companyId)
                .eq(PcMtlCheck::getRecFlag, "Y")
                .like(!request.getRecNo().isEmpty(), PcMtlCheck::getRecNo, request.getRecNo())
                .like(!request.getPurLot().isEmpty(), PcMtlCheck::getPurLot, request.getPurLot())
                .like(!request.getMtlName().isEmpty(), PcMtlCheck::getMtlName, request.getMtlName())
                .le(request.getRecDateStart() != null, PcMtlCheck::getRecDate, request.getRecDateStart())
                .ge(request.getRecDateEnd() != null, PcMtlCheck::getRecDate, request.getRecDateEnd()).list();
        BigDecimal sendSum = list.stream()
                .map(PcMtlCheck::getSendQty)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        List<InStkDtlDto> dtos = BeanUtil.copyList(checks, InStkDtlDto.class);
        /*补充海关数据*/
        List<HgMtlRelation> relationList = new ArrayList<>();
        for (InStkDtlDto dto : dtos) {
            HgMtlRelation relation= new HgMtlRelation()
                    .setMtlNo(dto.getMtlNo())
                    .setMtlName(dto.getMtlName())
                    .setMtlColor(dto.getMtlColor())
                    .setMtlSpec(dto.getMtlSpec())
                    .setMtlUnit(dto.getMtlUnit());
            relationList.add(relation);
        }
        Map<String, HgMtlRelationVo> voMap = hgMtlService.detailMapQueryByMtlList(relationList);
        for (InStkDtlDto dto : dtos) {
            String key = Arrays.asList(
                    Optional.ofNullable(dto.getMtlNo()).orElse(""),
                    Optional.ofNullable(dto.getMtlName()).orElse(""),
                    Optional.ofNullable(dto.getMtlColor()).orElse(""),
                    Optional.ofNullable(dto.getMtlSpec()).orElse(""),
                    Optional.ofNullable(dto.getMtlUnit()).orElse("")
            ).toString();
            HgMtlRelationVo vo = voMap.get(key);
            if (vo != null) {
                dto.setHgId(vo.getHgId());
                dto.setMtlNoHg(vo.getMtlNoHg());
                dto.setMtlNameEng(vo.getMtlNameEng());
                dto.setHgRelId(vo.getRelId());
            }
        }

        /*封装输出*/
        Map<String, Object> map = new HashMap<>(3);
        map.put("total", page.getTotal());
        map.put("sendSum", sendSum);
        map.put("dtos", dtos);
        return ResponseInfo.ok(map);
    }

    @Override
    @Transactional
    public ResponseInfo delateByRecNo(String recNo) {
        /*判断数据是否存在*/
        List<PcMtlCheck> checks = lambdaQuery()
                .select(PcMtlCheck::getSysUser, PcMtlCheck::getRecNo)
                .eq(PcMtlCheck::getRecNo, recNo).list();
        if (checks.isEmpty()) {
            return ResponseInfo.error("入库单号不存在", DATA_IS_ERR.getCode());
        }
        String userName = UserIdThread.get().getUserName();
        if (!checks.get(0).getSysUser().equals(userName)) {
            log.warn("异常接口：delateByRecNo\n异常原因：尝试删除非本人数据，操作人：{}，单号：{}", userName, recNo);
        }
        /*删除数据*/
        String companyId = UserIdThread.get().getCompanyId();
        LambdaQueryWrapper<PcMtlCheck> wrapper = new LambdaQueryWrapper<PcMtlCheck>()
                .eq(PcMtlCheck::getCompanyId, companyId)
                .eq(PcMtlCheck::getRecNo, recNo);
        Map<String, BigDecimal> mtlNos = checkMapper.selectList(wrapper).stream().collect(Collectors.toMap(PcMtlCheck::getMtlNo, PcMtlCheck::getSendQty, BigDecimal::add));
        accMapper.stkReduceByMap(mtlNos, companyId);
        checkMapper.delete(wrapper);
        return ResponseInfo.ok("数据删除成功");
    }

    @Override
    public ResponseInfo deleteRow(Integer id) {
        SysUserTokenDTO tokenDTO = UserIdThread.get();
        String userName = tokenDTO.getUserName();
        String companyId = tokenDTO.getCompanyId();
        /*判断数据是否存在*/
        PcMtlCheck check = checkMapper.selectById(id);
        if (check==null||!companyId.equals(check.getCompanyId())) {
            log.error("异常接口：deleteRow\n异常原因:无法找到对应数据，ID:{}\n异常表：【PC_MTL_CHECK】", id);
            return ResponseInfo.error("该数据已删除", DATA_IS_ERR.getCode());
        }
        /*判断是否是当前成员操作*/
        if (!check.getSysUser().equals(userName)) {
            log.warn("异常接口：deleteRow\n异常原因：尝试删除非本人数据，操作人：{}，数据：{}", userName,id);
            return ResponseInfo.error("无法删除非本人数据", USER_IS_ERR.getCode());
        }
        /*判断是否检核*/
        if ("Y".equals(check.getCfmFlag())){
            throw new ServiceErrorException("数据已检核，无法删除");
        }
        /*删除数据*/
        Map<String, BigDecimal> mtlNos = new HashMap<>();
        mtlNos.put(check.getMtlNo(), check.getSendQty());
        accMapper.stkReduceByMap(mtlNos, companyId);
        checkMapper.deleteById(id);
        return ResponseInfo.ok("删除成功");
    }

    @Override
    @Transactional
    public ResponseInfo sendQtyUpdate(Integer id, BigDecimal sendQty) {
        SysUserTokenDTO tokenDTO = UserIdThread.get();
        String companyId = tokenDTO.getCompanyId();
        /*判断是否是创建人操作*/
        PcMtlCheck check = checkMapper.selectById(id);
        if (check==null){
            throw new ServiceErrorException("无效数据");
        }
        String userName = tokenDTO.getUserName();
        if (!check.getSysUser().equals(userName)) {
            return ResponseInfo.error("无法修改非本人数据", USER_IS_ERR.getCode());
        }
        /*判断数量是否充足*/
        if (check.getSendQty().compareTo(sendQty) > 0){
            LambdaQueryWrapper<PcMtlAcc> accWrapper = new LambdaQueryWrapper<PcMtlAcc>()
                    .eq(PcMtlAcc::getCompanyId, companyId)
                    .eq(PcMtlAcc::getMtlNo,check.getMtlNo())
                    .eq(PcMtlAcc::getMtlName, check.getMtlName())
                    .eq(StringUtils.isNotBlank(check.getMtlColor()),PcMtlAcc::getMtlColor, check.getMtlColor())
                    .isNull(StringUtils.isBlank(check.getMtlColor()),PcMtlAcc::getMtlColor)
                    .eq(StringUtils.isNotBlank(check.getMtlSpec()),PcMtlAcc::getMtlSpec, check.getMtlSpec())
                    .isNull(StringUtils.isBlank(check.getMtlSpec()),PcMtlAcc::getMtlSpec)
                    .eq(StringUtils.isNotBlank(check.getMtlUnit()),PcMtlAcc::getMtlUnit, check.getMtlUnit())
                    .isNull(StringUtils.isBlank(check.getMtlUnit()),PcMtlAcc::getMtlUnit)
                    .last("LIMIT 1");
            PcMtlAcc mtlAcc = accMapper.selectOne(accWrapper);
            if (mtlAcc==null||mtlAcc.getStkQty()==null){
                log.error("\n错误接口：sendQtyUpdate\n错误原因：库存异常\n物料ID：{}", check.getMtlNo());
                throw new ServiceErrorException("库存余量异常");
            }if (mtlAcc.getStkQty().compareTo(check.getSendQty().subtract(sendQty))<0){
                log.warn("异常接口：sendQtyUpdate\n异常原因：库存不足，剩余库存：{}，暂收将会减少库存：{}", mtlAcc.getStkQty(), check.getSendQty().subtract(sendQty));
                return ResponseInfo.error("库存不足", INPUT_ERROR.getCode());
            }
        }
        /*修改库存*/
        PcMtlAcc mtlAcc = new PcMtlAcc()
                .setMtlNo(check.getMtlNo())
                .setMtlName(check.getMtlName())
                .setMtlColor(check.getMtlColor())
                .setMtlUnit(check.getMtlUnit())
                .setMtlSpec(check.getMtlSpec())
                .setInQty(sendQty.subtract(check.getSendQty()))
                .setRecDate(LocalDate.now().atStartOfDay())
                .setCompanyId(companyId);
        accMapper.stkUpByMtl(mtlAcc);
        /*修改数据*/
        LambdaUpdateWrapper<PcMtlCheck> wrapper = new LambdaUpdateWrapper<PcMtlCheck>()
                .eq(PcMtlCheck::getPrimaryId, id)
                .set(PcMtlCheck::getAcceptQty, sendQty);
        checkMapper.update(null, wrapper);
        return ResponseInfo.ok("修改成功");
    }

    @Override
    public void otherDateUpdate(OtherStockUpRequest request, String recNo) {
        /*获取数据*/
        LambdaUpdateWrapper<PcMtlCheck> wrapper = new LambdaUpdateWrapper<PcMtlCheck>()
                .eq(PcMtlCheck::getRecNo, recNo);
        /*判断数据是否存在*/
        List<PcMtlCheck> checks =checkMapper.selectList(wrapper);
        if (ArrayUtils.isEmpyt(checks)) {
            log.error("无法找到入库单号对应数据，REC_NO:{}", recNo);
            throw new ServiceErrorException("入库单号不存在");
        }
        /*判断是否是数据创建人操作*/
        String userName = UserIdThread.get().getUserName();
        if (!checks.get(0).getSysUser().equals(userName)) {
            throw new ServiceErrorException("无法操作非本人数据");
        }
        /*已检核不能修改*/
        long count = checks.stream().filter(c -> "Y".equals(c.getCfmFlag())).count();
        if (count>0){
            throw new ServiceErrorException("已检核,无法修改");
        }
        /*修改数据*/
        wrapper.set(request.getSendDateUp()!=null,PcMtlCheck::getSendDate, request.getSendDateUp())
                .set(StringUtil.isNotBlank(request.getSendNoUp()),PcMtlCheck::getSendNo, request.getSendNoUp())
                .set(StringUtil.isNotBlank(request.getVendorNoUp()),PcMtlCheck::getVendorNo, request.getVendorNoUp())
                .set(StringUtil.isNotBlank(request.getVendorNameUp()),PcMtlCheck::getVendorName, request.getVendorNameUp())
                .set(PcMtlCheck::getKgQty, request.getKgQtyUp());
        checkMapper.update(null, wrapper);
    }

    @Override
    public ResponseInfo mtlSubQuery(MtlSubQueryRequest request) {
        /*获取数据*/
        LambdaQueryWrapper<PcDrawReplace2> wrapper = new LambdaQueryWrapper<PcDrawReplace2>()
                .like(!request.getRecNo().isEmpty(), PcDrawReplace2::getSlipNo, request.getRecNo())
                .like(!request.getLotNo().isEmpty(), PcDrawReplace2::getLotNo, request.getLotNo())
                .like(!request.getMtlName().isEmpty(), PcDrawReplace2::getMtlName, request.getMtlName())
                .like(!request.getMtlName2().isEmpty(), PcDrawReplace2::getMtlName2, request.getMtlName2())
                .isNotNull(PcDrawReplace2::getLotNo)
                .orderByAsc(PcDrawReplace2::getSlipNo);
        List<PcDrawReplace2> replace2s = replace2Mapper.selectList(wrapper);
        List<MtlSubDto> dtos = BeanUtil.copyList(replace2s, MtlSubDto.class);
        /*判空*/
        if (dtos != null && dtos.isEmpty()) {
            return ResponseInfo.ok();
        }
        return ResponseInfo.ok(dtos);
    }

    @Override
    public ResponseInfo inStockMtlSub(MtlSubAddRequest request) {
        /*收集新增用数据*/
        PcDrawReplace2 replace = BeanUtil.copyBean(request, PcDrawReplace2.class);
        replace.setSlipNo(request.getRecNo());
        replace.setQty(request.getSendQty());
        /*新增*/
        replace2Mapper.insert(replace);
        return ResponseInfo.ok("替换成功");
    }

    @Override
    @AutoPageAop
    public ResponseInfo subMtlQuery(SubMtlQueryRequest request) {
        /*获取数据*/
        List<SubMtlDto> dtos = accMapper.subMtlQuery(request);
        Page<SubMtlDto> page = (Page<SubMtlDto>) dtos;
        /*封装数据*/
        Map map = new HashMap();
        map.put("total", page.getTotal());
        map.put("dtos", dtos);
        return ResponseInfo.ok(map);
    }

    @Override
    public ResponseInfo mtlSubUpdate(List<MtlSubUpdateRequest> request) {
        /*更新数据*/
        replace2Mapper.mtlSubUpdate(request);
        return ResponseInfo.ok("更新成功");
    }

    @Override
    public ResponseInfo MtlSubProcess(MtlSubProcRequest request) {
        /*判断入参是否正确*/
        if (request.getOutType() != null) {
            return ResponseInfo.error("已处理数据不可重复处理", INPUT_ERROR.getCode());
        }
        if (request.getMtlNo2() == null) {
            return ResponseInfo.error("替代材料不可为空", INPUT_ERROR.getCode());
        }
        if (request.getMtlNo().equals(request.getMtlNo2())) {
            return ResponseInfo.error("替换前后的材料ID相同", INPUT_ERROR.getCode());
        }
        LambdaQueryWrapper<PcMtlAcc> acc_1Wrapper = new LambdaQueryWrapper<PcMtlAcc>()
                .select(PcMtlAcc::getMtlNo)
                .eq(PcMtlAcc::getMtlNo, request.getMtlNo())
                .last("limit 1");
        LambdaQueryWrapper<PcMtlAcc> acc_2Wrapper = new LambdaQueryWrapper<PcMtlAcc>()
                .select(PcMtlAcc::getMtlNo, PcMtlAcc::getStkQty)
                .eq(PcMtlAcc::getMtlNo, request.getMtlNo2())
                .last("limit 1");
        int acc_1 = accMapper.selectCount(acc_1Wrapper);
        PcMtlAcc acc_2 = accMapper.selectOne(acc_2Wrapper);
        if (acc_1 != 0) {
            return ResponseInfo.error("替代前物料编码存在于指令用料表中\n不能替换", INPUT_ERROR.getCode());
        }
        if (acc_2 == null) {
            return ResponseInfo.error("替换后物料编码不存在于指令用量表中\n不能替换", INPUT_ERROR.getCode());
        }
        if (acc_2.getStkQty().compareTo(request.getQty2()) < 0) {
            log.error("材料替换库存不足\n库存数量为：{}\n需求数量为：{}", acc_2.getStkQty(), request.getQty2());
            return ResponseInfo.error("库存数量不足");
        }
        /*更新数据*/
        replace2Mapper.MtlSubProcess(request);
        return ResponseInfo.ok("更新成功");
    }

    @Override
    public void mtlNoHgUpdate(HgMtlRelation relation) {
        if (relation.getHgId() == null) {
            return;
        }if (relation.getHgRelId() == null){
            hgMtlService.detailAdd(relation);
        }else {
            hgMtlService.detailUpByMtl(relation);
        }
    }

    /**
     * 获取查询一条指定明细数据对应的wrapper
     *
     * @return wrapper
     */
    private LambdaUpdateWrapper<PcMtlCheck> getOneStock(PurSentRequest request) {
        /*获取数据*/
        LambdaUpdateWrapper<PcMtlCheck> wrapper = new LambdaUpdateWrapper<PcMtlCheck>()
                .eq(PcMtlCheck::getCompanyId,UserIdThread.get().getCompanyId())
//                .eq(PcMtlCheck::getSysUser,userName)
                .eq(PcMtlCheck::getPurNo, request.getPurNo())
                .eq(PcMtlCheck::getReqNo, request.getReqNo())
                .eq(PcMtlCheck::getPurLot, request.getPurLot())
                .eq(request.getMtlColor() != null && !request.getMtlColor()
                        .isEmpty(), PcMtlCheck::getMtlColor, request.getMtlColor())
                .eq(PcMtlCheck::getMtlName, request.getMtlName())
                .eq(PcMtlCheck::getSendQty, request.getSendQty())
                .eq(PcMtlCheck::getVendorName, request.getVendorName())
                .eq(PcMtlCheck::getSendNo, request.getSendNo())
                .eq(PcMtlCheck::getRecNo, request.getRecNo())
                .eq(PcMtlCheck::getSlipType, request.getSlipType())
                .last("limit 1");
        return wrapper;
    }
}
